from socketserver import TCPServer, StreamRequestHandler
import numpy as np
import random as rd
from pylab import *
import codecs

NN = 20
AI = True

data = {}
data['valid'] = np.zeros(NN)
data['Temp'] = np.zeros(NN)
data['HR'] = np.zeros(NN)
data['SpO2'] = np.zeros(NN)
data['Acc'] = np.zeros((NN, 6))
data_ptr = 0
data_index = 0
pro_data = {}
pro_data['HR'] = np.zeros(NN)
pro_data['SpO2'] = np.zeros(NN)
pro_data['Acc'] = np.zeros((NN, 5))

xx = np.linspace(1, 100000, 100000)

fig = figure(figsize=(12, 6))
ax_temp = fig.add_subplot(221)
ax_hr = fig.add_subplot(222)
ax_spo2 = fig.add_subplot(223)
ax_acc = fig.add_subplot(224)

if (AI):
    import keras
    import tensorflow as tf
    config = tf.compat.v1.ConfigProto(allow_soft_placement=True)
    config.gpu_options.per_process_gpu_memory_fraction = 0.90
    config.gpu_options.allow_growth = True
    tf.compat.v1.keras.backend.set_session(tf.compat.v1.Session(config=config))
    model = keras.models.load_model('model.h5')
    data_notif = np.zeros((2, 35), dtype=float)
    with codecs.open('model_notif.txt', "r", encoding='utf-8') as file:
        for i in range(2):
            for j in range(35):
                data_notif[i][j] = float(file.readline().strip())


class Handler(StreamRequestHandler):
    def handle(self):
        addr = self.request.getpeername()
        print('Got connection from', addr)
        self.wfile.write(b'Thank you for connecting')
        print('\x1b[2J')  # clear screen

        ion()

        global ax_temp, ax_hr, ax_spo2
        ax_temp.set_xlabel(r'$Time$')
        ax_temp.set_ylabel(r'$Value( ^{o}C)$')
        ax_temp.set_title(r'$Temprature$')

        ax_hr.set_xlabel(r'$Time$')
        ax_hr.set_ylabel(r'$BPM$')
        ax_hr.set_title(r'$Heart Rate$')

        ax_spo2.set_xlabel(r'$Time$')
        ax_spo2.set_ylabel(r'$SpO2(%%)$')
        ax_spo2.set_title(r'$SpO2$')

        ax_acc.set_xlabel(r'$Time$')
        ax_acc.set_ylabel(r'$Value(\frac{16}{1000\dot (mg)^2)}$')
        ax_acc.set_title(r'$Acc$')

        while 1:
            imfor = self.rfile.readline().decode().strip()
            # print(imfor)
            if imfor == "batch":
                self.norm_display(imfor)
                self.wfile.write(b'end')
            else:
                print("unknown info:{}".format(imfor))

    def norm_display(self, tag):
        temp_raw = [0]
        temp_data = [0]
        while True:
            try:
                temp = self.rfile.readline().decode().strip()
                len = int(temp)
                # print(temp)
                break
            except ValueError:
                print("Error : "+temp)
        while True:
            try:
                for i in range(1, 11):
                    temp_raw.append(self.rfile.readline().decode().strip())
                temp_data.append(int(temp_raw[1]))
                for i in range(2, 11):
                    temp_data.append(double(temp_raw[i]))

                break
            except ValueError:
                print("Error : "+temp)

        global ax_temp, ax_hr, ax_spo2
        global data, data_ptr, data_index

        if (temp_data[3] > 200) or (temp_data[3] < 30):
            temp_data[1] = 0
        data['valid'][data_ptr] = temp_data[1]
        data['Temp'][data_ptr] = temp_data[2]
        data['HR'][data_ptr] = temp_data[3]
        data['SpO2'][data_ptr] = temp_data[4]
        for i in range(6):
            data['Acc'][data_ptr][i] = temp_data[i+5]
        data_index += 1
        data_ptr += 1
        if (data_ptr >= NN):
            data_ptr -= NN

        rate_sum = 0
        rate_num = 0
        spo2_sum = 0
        spo2_num = 0
        ml_state = "NULL"
        valid_arr = np.concatenate(
            [data['valid'][data_ptr:NN], data['valid'][0:data_ptr]])
        rate_arr = np.concatenate(
            [data['HR'][data_ptr:NN], data['HR'][0:data_ptr]])
        spo2_arr = np.concatenate(
            [data['SpO2'][data_ptr:NN], data['SpO2'][0:data_ptr]])
        for i in range(1, 11):
            if (valid_arr[NN-i] == 1):
                rate_sum += rate_arr[NN-i]
                spo2_sum += spo2_arr[NN-i]
                rate_num += 1
                spo2_num += 1
        if (rate_num > 0):
            rate_ave = rate_sum/rate_num
            spo2_ave = spo2_sum/spo2_num
        else:
            rate_ave = 0
            spo2_ave = 0
        pro_data['HR'][data_ptr-1] = rate_ave
        pro_data['SpO2'][data_ptr-1] = spo2_ave
        for i in range(5):
            pro_data['Acc'][data_ptr-1][i] = data['Acc'][data_ptr-1][i+1]-data['Acc'][data_ptr-1][i]

        if (temp_data[1] == 1):
            print('#{} : Temp : {:.3f}℃, HR : {:.0f}bpm, SpO2 : {:.1f}%'.format(
                data_index, temp_data[2], temp_data[3], temp_data[4]))
        else:
            print('#{} : Temp : {:.3f}℃, HR : {:.0f}bpm, SpO2 : {:.1f}%, INVALID'.format(
                data_index, temp_data[2], temp_data[3], temp_data[4]))

        print('### Heart Rate : {:.0f}bpm, SpO2 : {:.3f}%, Temp: {:.2f}℃'.format(
            rate_ave, spo2_ave, temp_data[2]))

        if (sum(valid_arr[-5:]) == 5):  # save the data
            with codecs.open('output.txt', "a", encoding='utf-8') as file:
                for i in range(data_ptr-5, data_ptr, 1):
                    file.write('{:.0f} {:.3f} '.format(
                        pro_data['HR'][i], pro_data['SpO2'][i]))
                    for j in range(5):
                        file.write('{:.0f} '.format(pro_data['Acc'][i][j]))
                # 0 stands for quite/peace; 1 stands for walk; 2 stands for fierce movation
                file.write('2\n')
            print("A new save!")
            if (AI):
                x = []
                for i in range(data_ptr-5, data_ptr, 1):
                    x.append(pro_data['HR'][i])
                    x.append(pro_data['SpO2'][i])
                    for j in range(5):
                        x.append(pro_data['Acc'][i][j])
                x = np.array(x, dtype=float)
                x -= data_notif[0]
                x /= data_notif[1]
                x = np.reshape(x,(1,35))
                y = model.predict(x)[0]
                if (np.argmax(y)==0):
                    ml_state="QUITE & PEACE {:.2f}%".format(y[np.argmax(y)]*100)
                elif (np.argmax(y)==1):
                    ml_state="WALKING {:.2f}%".format(y[np.argmax(y)]*100)
                elif (np.argmax(y)==2):
                    ml_state="RUNNING {:.2f}%".format(y[np.argmax(y)]*100)
                print("-- ", ml_state, " --")

        for ax, tag in zip([ax_temp, ax_hr, ax_spo2, ax_acc], ['Temp', 'HR', 'SpO2', 'Acc']):
            ax.cla()
            if (tag == 'Temp'):
                ax.set_xlabel(r'$Time$')
                ax.set_ylabel(r'$Value( ^{o}C)$')
                ax.set_title(r'$Temprature$')
            elif (tag == 'HR'):
                ax.set_xlabel(r'$Time$')
                ax.set_ylabel(r'$BPM$')
                ax.set_title(r'$Heart Rate$')
            elif (tag == 'SpO2'):
                ax.set_xlabel(r'$Time$')
                ax.set_ylabel(r'$SpO2(%%)$')
                ax.set_title(r'$SpO2$')
                if (AI):
                    ax.text(19, 102, ml_state)
            elif (tag == 'Acc'):
                ax.set_xlabel(r'$Time$')
                ax.set_ylabel(r'$Value(\frac{16}{1000\dot (mg)^2})$')
                ax.set_title(r'$Acc$')
            ax.grid()
            if (tag == 'Acc'):
                ax.set_xlim(1, NN*6)
            else:
                ax.set_xlim(1, NN)
            if (tag == 'Temp'):
                ax.set_ylim(min(data[tag])-0.5, max(data[tag])+0.5)
            elif (tag == 'HR'):
                ax.set_ylim(min(pro_data[tag])-30, max(pro_data[tag])+30)
            elif (tag == 'SpO2'):
                ax.set_ylim(70, 101)
            elif (tag == 'Acc'):
                ax.set_ylim(min(data[tag].reshape(NN*6)) -
                            300, max(data[tag].reshape(NN*6))+300)
            if (tag == 'HR') or (tag == 'SpO2'):
                ax.plot(xx[0:NN], np.concatenate(
                    [pro_data[tag][data_ptr:NN], pro_data[tag][0:data_ptr]]), 'k', linewidth=0.7)
            elif (tag == 'Temp'):
                ax.plot(xx[0:NN], np.concatenate(
                    [data[tag][data_ptr:NN], data[tag][0:data_ptr]]), 'k', linewidth=0.7)
            elif (tag == 'Acc'):
                ax.plot(xx[0:NN*6], np.concatenate(
                    [data[tag][data_ptr:NN], data[tag][0:data_ptr]]).reshape(NN*6), 'k', linewidth=0.7)
            pause(0.05)


server = TCPServer(('', 6666), Handler)
server.serve_forever()
